#include "flObj.h"

// Defaults constructor
flObj::flObj()
{
	model = NULL;
	maxA = new float[3];
	minA = new float[3];
	dist = new float[3];
}
// Default destructor
flObj::~flObj()
{
	model = NULL;
}

flObj::flObj(string _objPath)
{
	objPath = _objPath;
	model = NULL;
	maxA = new float[3];
	minA = new float[3];
	dist = new float[3];
}

void flObj::load()
{
	if(!model)
	{
		model = glmReadOBJ((char *)objPath.c_str());	// Reads the model
		if(!model)
		{
			printf("Couldn't load model: %s", objPath);
			return;
		}
		// This will rescale the object to fit into the unity matrix
		// Depending on your project you might want to keep the original size and 
		// positions you had in 3DS Max or GMAX so you may have to comment this.
		glmUnitize(model);
		// These 2 functions calculate triangle and vertex normals from the geometry data.
		// To be honest I had some problem with very complex models that didn't look to good 
		// because of how vertex normals were calculated
		// So if you can export these directly from you modeling tool do it and comment these line
		// 3DS Max can calculate these for you and GLM is perfectly capable of loading them
		glmFacetNormals(model);
		glmVertexNormals(model, 90.0);
		// Populates the array
		populateMaxMin();
	}
}

void flObj::setAAbox(float x, float y, float z)
{
	Vec3 corner(maxA[0], maxA[1], maxA[2]);
	aab.setBox(corner, x, y, z);
}

void flObj::load(string _objPath)
{
	objPath = _objPath;
	if(!model)
	{
		model = glmReadOBJ((char *)objPath.c_str());
		if(!model)
		{
			printf("Couldn't load model: %s", objPath);
			return;
		}
		glmUnitize(model);
		glmFacetNormals(model);
		glmVertexNormals(model, 90.0);

		populateMaxMin();
	}
}

// Draws the model
void flObj::draw()
{
	bool lightIsOn = glIsEnabled(GL_LIGHTING);
	if(lightIsOn)					// Lights OFF
		glDisable(GL_LIGHTING);
	// This is the call that will actualy draw the model
	// Don't forget to tell it if you want textures or not :))		
	glmDraw(model, GLM_SMOOTH | GLM_TEXTURE);

	if(lightIsOn)					// Lights ON
		glEnable(GL_LIGHTING);
}

void flObj::drawWiredBBox()	// Draws the bounding box
{
	bool lightIsOn = glIsEnabled(GL_LIGHTING);
	if(lightIsOn)
		glDisable(GL_LIGHTING);

	glBegin(GL_LINE_STRIP);
		glVertex3f(minA[0], minA[1], maxA[2]);	// 0
		glVertex3f(maxA[0], minA[1], maxA[2]);	// 1
		glVertex3f(maxA[0], maxA[1], maxA[2]);	// 2
		glVertex3f(minA[0], maxA[1], maxA[2]);	// 3
		glVertex3f(minA[0], minA[1], maxA[2]);	// 0
	glEnd();
	glBegin(GL_LINE_STRIP);
		glVertex3f(minA[0], minA[1], maxA[2]);	// 0
		glVertex3f(maxA[0], minA[1], maxA[2]);	// 1
		glVertex3f(maxA[0], minA[1], minA[2]);	// 5
		glVertex3f(minA[0], minA[1], minA[2]);	// 4
		glVertex3f(minA[0], minA[1], maxA[2]);	// 0
	glEnd();
	glBegin(GL_LINE_STRIP);
		glVertex3f(minA[0], maxA[1], maxA[2]);	// 3
		glVertex3f(maxA[0], maxA[1], maxA[2]);	// 2
		glVertex3f(maxA[0], maxA[1], minA[2]);	// 6
		glVertex3f(minA[0], maxA[1], minA[2]);	// 7
		glVertex3f(minA[0], maxA[1], maxA[2]);	// 3
	glEnd();
	glBegin(GL_LINE_STRIP);
		glVertex3f(minA[0], minA[1], minA[2]);	// 4
		glVertex3f(maxA[0], minA[1], minA[2]);	// 5
		glVertex3f(maxA[0], maxA[1], minA[2]);	// 6
		glVertex3f(minA[0], maxA[1], minA[2]);	// 7
		glVertex3f(minA[0], minA[1], minA[2]);	// 4
	glEnd();

	if(lightIsOn)
		glEnable(GL_LIGHTING);
}

void flObj::drawSolidBBox()
{
	bool lightIsOn = glIsEnabled(GL_LIGHTING);
	if(lightIsOn)
		glDisable(GL_LIGHTING);

	glBegin(GL_QUADS);
		glVertex3f(minA[0], minA[1], maxA[2]);	// 0
		glVertex3f(maxA[0], minA[1], maxA[2]);	// 1
		glVertex3f(maxA[0], maxA[1], maxA[2]);	// 2
		glVertex3f(minA[0], maxA[1], maxA[2]);	// 3
	glEnd();
	glBegin(GL_QUADS);
		glVertex3f(minA[0], minA[1], maxA[2]);	// 0
		glVertex3f(maxA[0], minA[1], maxA[2]);	// 1
		glVertex3f(maxA[0], minA[1], minA[2]);	// 5
		glVertex3f(minA[0], minA[1], minA[2]);	// 4
	glEnd();
	glBegin(GL_QUADS);
		glVertex3f(minA[0], maxA[1], maxA[2]);	// 3
		glVertex3f(maxA[0], maxA[1], maxA[2]);	// 2
		glVertex3f(maxA[0], maxA[1], minA[2]);	// 6
		glVertex3f(minA[0], maxA[1], minA[2]);	// 7
	glEnd();
	glBegin(GL_QUADS);
		glVertex3f(minA[0], minA[1], minA[2]);	// 4
		glVertex3f(maxA[0], minA[1], minA[2]);	// 5
		glVertex3f(maxA[0], maxA[1], minA[2]);	// 6
		glVertex3f(minA[0], maxA[1], minA[2]);	// 7
	glEnd();

	if(lightIsOn)
		glEnable(GL_LIGHTING);
}

void flObj::drawWiredBSphere()	 // Draws the bounding sphere
{
	bool lightIsOn = glIsEnabled(GL_LIGHTING);
	if(lightIsOn)
		glDisable(GL_LIGHTING);

	// position
	float x = (dist[0] / 2) + minA[0];
	float y = (dist[1] / 2) + minA[1];
	float z = (dist[2] / 2) + minA[2];

	glBegin(GL_POINTS);
		glVertex3f(x, y, z);	// Sets a point in the center of the sphere
	glEnd();

	glutWireSphere(rad, 10, 10);

	if(lightIsOn)
		glEnable(GL_LIGHTING);
}

void flObj::populateMaxMin()
{
	glmMaxMin(model, maxA, minA);	// Gets the Max[x.y.z] and Min[x.y.z] of the model

	dist[0] = maxA[0] - minA[0];	// x
	dist[1] = maxA[1] - minA[1];	// y
	dist[2] = maxA[2] - minA[2];	// z

	float maxDist = 0.;				// Gets the max distance
	for(int i = 0; i < 3; i++)
	{
		if(dist[i] > maxDist)
			maxDist = dist[i];
	}

	rad = maxDist / 2;				// Sets the radious
}